﻿/************************************************************************************
 * xujiajun@yoozoo.com 御剑
 * LOD控制策略抽象类
 ***********************************************************************************/

using System;
using System.Collections.Generic;

namespace WorldMapBase.LOD
{
    /// <summary>
    /// LOD控制策略抽象类
    /// </summary>
    public abstract class LODStrategy
    {

        public const float LOD_PERCENT_TOLERANCE = 0.01f;
        
        /// <summary>
        /// 策略ID
        /// </summary>
        internal int id;

        /// <summary>
        /// LOD参数变化监听器列表
        /// </summary>
        private List<ILODListener> m_LODListenerList = new List<ILODListener>(10);

        /// <summary>
        /// LOD参数变化监听器的数量
        /// </summary>
        private int m_LODListenerCnt;

        /// <summary>
        /// 上一次LOD等级
        /// </summary>
        private int m_LastLODLevel;

        /// <summary>
        /// 上一次LOD百分比
        /// </summary>
        private float m_LastNextLODPercent;

        /// <summary>
        /// 刚刚添加进行来的监听器列表
        /// </summary>
        private List<ILODListener> m_AddedLODListenerList = new List<ILODListener>(10);

        /// <summary>
        /// 刚刚添加进行来的监听器数量
        /// </summary>
        private int m_AddedLODListenerCnt;

        /// <summary>
        /// 添加指定LOD变化的监听器
        /// </summary>
        /// <param name="listener">监听器对象</param>
        public void AddLODListener(ILODListener listener)
        {
            if (listener != null)
            {
                m_LODListenerList.Add(listener);
                m_LODListenerCnt++;
                m_AddedLODListenerList.Add(listener);
                m_AddedLODListenerCnt++;
            }
        }

        /// <summary>
        /// 移除指定LOD变化的监听器
        /// </summary>
        /// <param name="listener">监听器对象</param>
        public void RemoveLODImplement(ILODListener listener)
        {
            if (listener != null)
            {
                if (m_LODListenerList.Remove(listener))
                {
                    m_LODListenerCnt--;
                }
                if (m_AddedLODListenerList.Remove(listener))
                {
                    m_AddedLODListenerCnt--;
                }
            }
        }

        /// <summary>
        /// 移除所有LOD参数变化监听器
        /// </summary>
        public void RemoveAllLODImplements()
        {
            m_LODListenerList.Clear();
            m_LODListenerCnt = 0;
        }

        /// <summary>
        /// 内部调用。创建策略
        /// </summary>
        internal void Create()
        {
            m_LastLODLevel = -1;
            m_LastNextLODPercent = -1;
            OnCreate();
        }

        /// <summary>
        /// 内部调用。销毁策略
        /// </summary>
        internal void Destroy()
        {
            OnDestroy();
            RemoveAllLODImplements();
        }

        /// <summary>
        /// 内部调用
        /// </summary>
        internal void Update()
        {
            OnUpdate();

            var currentLODLevel = GetLODLevel();
            var currentNextLODPercent = GetNextLODPercent();
            var lodLevelChanged = false;

            // 检测LOD等级是否发生变化
            if (m_LastLODLevel != currentLODLevel)
            {
                for (int i = m_LODListenerCnt - 1; i >= 0; i--)
                {
                    m_LODListenerList[i].OnLODLevelChange(currentLODLevel, m_LastLODLevel);
                }
                m_LastLODLevel = currentLODLevel;
                lodLevelChanged = true;
            }
            // 针对刚刚添加进来的监听者，如果该帧内LOD没有发生变化，则强制进行一次通知用于初始化
            else if (m_AddedLODListenerCnt > 0)
            {
                for (int i = m_AddedLODListenerCnt - 1; i >= 0; i--)
                {
                    m_AddedLODListenerList[i].OnLODLevelChange(currentLODLevel, -1);
                }
            }

            //Debug.LogError("检测百分比：" + m_LastNextLODPercent);
            
            // 检测距离下一个LOD等级进度百分比是否发生变化
            if (Math.Abs(m_LastNextLODPercent - currentNextLODPercent) > LOD_PERCENT_TOLERANCE || lodLevelChanged)
            {
                for (int i = m_LODListenerCnt - 1; i >= 0; i--)
                {
                    m_LODListenerList[i].OnNextLODPercentUpdate(currentLODLevel, currentNextLODPercent);
                }
                m_LastNextLODPercent = currentNextLODPercent;
            }
            // 针对刚刚添加进来的监听者，如果该帧内没有通知LOD百分比变化，则强制进行一次通知用于初始化
            else if (m_AddedLODListenerCnt > 0)
            {
                for (int i = m_AddedLODListenerCnt - 1; i >= 0; i--)
                {
                    m_AddedLODListenerList[i].OnNextLODPercentUpdate(currentLODLevel, currentNextLODPercent);
                }
            }

            // 将刚刚添加进来的监听者列表清空
            if (m_AddedLODListenerCnt > 0)
            {
                m_AddedLODListenerCnt = 0;
                m_AddedLODListenerList.Clear();
            }
        }

        /// <summary>
        /// 获取当前LOD等级
        /// </summary>
        /// <returns></returns>
        public abstract int GetLODLevel();

        /// <summary>
        /// 获取距离下一个LOD等级进度百分比（0-99）
        /// </summary>
        /// <returns></returns>
        public abstract float GetNextLODPercent();

        /// <summary>
        /// 创建时响应
        /// </summary>
        protected abstract void OnCreate();

        /// <summary>
        /// 销毁时响应
        /// </summary>
        protected abstract void OnDestroy();

        /// <summary>
        /// 更新时响应
        /// </summary>
        protected abstract void OnUpdate();
    }
}
